#!/usr/bin/ python3
# -*- coding: utf-8 -*-

# @Time : 18-12-12 上午11:14
# @Author : Qiang Yang
# @Email : mmmyq@126.com
# @File : SDLSO.py
# @Project : SDLSO_Python


import numpy as np
import sys
import math
import time
from cec2013lsgo import cec2013


# get the function_id and the number of runs
function_id = int(sys.argv[1])
total_run = int(sys.argv[2])

# function_id = 1
# total_run = 1

# set parameters for SDLSO
population_size = 400
dim = 1000
fitness_evaluations = 3000*dim

# get the information of the corresponding function
benchmark = cec2013.Benchmark()
function_info = benchmark.get_info(function_id)
lbound = function_info['lower']
ubound = function_info['upper']
function_handle = benchmark.get_function(function_id)

small_value = 1e-50

out_file = './Results/Function_'+str(function_id)+'.txt'
out_result = open(out_file, 'w')

# start to run
run_index = 0
while(run_index < total_run):
    benchmark.next_run()

    start_time = time.time()

    # initialization
    gbest_index = -1
    gbest_fitness = 1e100
    fes_count = 0

    velocity = np.zeros((population_size, dim))
    fitness = np.zeros(population_size)
    position = np.ones((population_size, dim)) * lbound + np.random.rand(population_size, dim)*(ubound-lbound)

    for i in range(population_size):
        fitness[i] = function_handle(position[i])
        if fitness[i] < gbest_fitness:
            gbest_fitness = fitness[i]
            gbest_index = i

    gbest = position[gbest_index]

    fes_count = fes_count + population_size

    while fes_count < fitness_evaluations:
        # update population
        for i in range(population_size):
            # randomly select two exemplars
            exemplar1 = np.random.randint(0, population_size, 1)
            while exemplar1 == i:
                exemplar1 = np.random.randint(0, population_size, 1)

            exemplar2 = np.random.randint(0, population_size, 1)
            while exemplar2 == i or exemplar2 == exemplar1:
                exemplar2 = np.random.randint(0, population_size, 1)

            if fitness[exemplar1] <= fitness[i] and fitness[exemplar2] <= fitness[i]:
                if fitness[exemplar2] < fitness[exemplar1]:
                    exemplar1, exemplar2 = exemplar2, exemplar1

                # compute PHI
                phi = 0.5-0.2*math.exp(-1*(fitness[i]-fitness[exemplar2]+small_value)/(fitness[i]-fitness[exemplar1]+small_value))

                # update particle
                r1 = np.random.rand(3, dim)
                velocity[i] = r1[0] * velocity[i] + r1[1] * (position[exemplar1] - position[i]) + r1[2] * phi * (position[exemplar2] - position[i])
                position[i] = position[i] + velocity[i]

                position[i][position[i] < lbound] = lbound
                position[i][position[i] > ubound] = ubound

                fitness[i] = function_handle(position[i])
                fes_count = fes_count + 1

                if fitness[i] < gbest_fitness:
                    gbest_fitness = fitness[i]
                    gbest = position[i]
        if fes_count % 1e4 == 0:
            print("After %d fitness evaluations, the gbest is %E: \n" % (fes_count, gbest_fitness))

    end_time = time.time()

    out_result.write("%E\t%f\n" % (gbest_fitness, end_time - start_time))

    print("The gbest of the %dth run is %E: \n" %  (run_index, gbest_fitness))
    print("The used time is %f: \n" % (end_time-start_time))

    run_index = run_index + 1

out_result.close()



